#!/usr/bin/env python
# -*- coding: UTF-8 -*-
###
#
# Gromlist is the legal property of Raul Gonzalez Duque <zootropo@gmail.com>
# Copyright (c) 2007 Raul Gonzalez Duque
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
###

import urllib, urllib2, xml.dom.minidom, sys, os, gtk, gobject, re, thread, threading
import ConfigParser
from zipfile import ZipFile
import zlib, binascii, struct # To calculate the CRC of a file
import gettext


class Game:
    pass


def download(url, output):
    """Download a file from the URL 'url' to the path 'output'"""
    inputFile = urllib2.urlopen(url)
    outputFile = open(output, "wb")

    for line in inputFile:
        outputFile.write(line)
    outputFile.close()


def decimal_to_binary(number):
    """Converts an integer to a string with its binary representation"""
    bStr = ""
    if number == 0: return "0"
    while number > 0:
        bStr = str(number % 2) + bStr
        number = number >> 1
    return bStr


def get_range(release_number):
    """Returns a string with the name of the folder in which the image is stored
    following the offlinelist convention of creating folders with 500 images."""
    imgCoc = (release_number - 1) / 500
    imgRangeStart = (imgCoc * 500) + 1
    imgRange = str(imgRangeStart) + "-" + str(imgRangeStart + 499)
    return imgRange


def display_selected_game(treeselection):
    """Called when the user clics on a game. It changes the details to those
    of the selected game."""
    global releaseNumber
    releaseNumber = 1

    if treeselection:
        (model, iter) = treeselection.get_selected()
        if iter:
            releaseNumber = model.get_value(iter, 2)

    game = games[int(releaseNumber)]

    image1.set_from_file(img_folder + "/" + dat_name + "/" + get_range(int(game.imageNumber)) + "/" + game.imageNumber + "a.png")
    image2.set_from_file(img_folder + "/" + dat_name + "/" + get_range(int(game.imageNumber)) + "/" + game.imageNumber + "b.png")
    lblTitle.set_markup("<span size=\"x-large\" weight=\"bold\">" + game.releaseNumber + " - " + game.title + "</span>")
    lblLocation.set_text(_("Location: ") + game.location)
    lblPublisher.set_text(_("Publisher: ") + game.publisher)
    lblSource.set_text(_("Source: ") + game.sourceRom)
    lblLanguage.set_text(_("Language: ") + game.language)

    wanted_tag_button.set_active(wanted.has_key(releaseNumber))
    played_tag_button.set_active(played.has_key(releaseNumber))
    buyed_tag_button.set_active(buyed.has_key(releaseNumber))


def write_tags():
    buyed_file = open(img_folder + "/" + dat_name + "/buyed", "wb")
    for game in buyed:
        buyed_file.write(str(game) + "\n")
    buyed_file.close()

    wanted_file = open(img_folder + "/" + dat_name + "/wanted", "wb")
    for game in wanted:
        wanted_file.write(str(game) + "\n")
    wanted_file.close()

    played_file = open(img_folder + "/" + dat_name + "/played", "wb")
    for game in played:
        played_file.write(str(game) + "\n")
    played_file.close()

    buyed.clear()
    wanted.clear()
    played.clear()


def read_tags():
    path = img_folder + "/" + dat_name + "/buyed"
    if os.path.exists(path):
        buyed_file = open(path, "r")
        for line in buyed_file.readlines():
            try:
                game = int(line)
                buyed[game] = True
            except (ValueError, IndexError):
                pass
        buyed_file.close()

    path = img_folder + "/" + dat_name + "/wanted"
    if os.path.exists(path):
        wanted_file = open(path, "r")
        for line in wanted_file.readlines():
            try:
                game = int(line)
                wanted[game] = True
            except (ValueError, IndexError):
                pass
        wanted_file.close()

    path = img_folder + "/" + dat_name + "/played"
    if os.path.exists(path):
        played_file = open(path, "r")
        for line in played_file.readlines():
            try:
                game = int(line)
                played[game] = True
            except (ValueError, IndexError):
                pass
        played_file.close()


def display_selected_dat(combobox=None, selected=None):
    """When the user selects a dat, dowload it from the internet, dowload the
    images, and load the game list."""
    if selected:
        active = selected
        comboboxDat.set_active(int(active))
        return
    else:
        active = combobox.get_active()
        write_tags()

    list_url = cfg.get("Dats", "url" + str(active))

    zip_name = list_url.rsplit("/")[-1]

    # If we haven't download it yet on this session, download the dat
    if not active in dats_downloaded.keys():
        try:
            statusbar.push(statusbar.get_context_id("Downloading dat"), _("Downloading dat file"))
            download(list_url, os.path.expanduser("~") + "/.gromlist/" + zip_name)
        except:
            statusbar.push(statusbar.get_context_id("Error"), _("The dat file cannot be downloaded"))
            print _("The dat file cannot be downloaded")
            return

        # Uncompress it to get the xml file
        zip_path = os.path.expanduser("~") + "/.gromlist/" + zip_name
        zip_file = ZipFile(zip_path, "r")
        for zipped_file in zip_file.namelist():
                found = re.search("(\S+).xml", zipped_file)
                if found:
                    file(os.path.expanduser("~") + "/.gromlist/" + zipped_file, "wb").write(zip_file.read(zipped_file))
        zip_file.close()

        xmlFile = os.path.expanduser("~") + "/.gromlist/" + found.group(1) + ".xml"
        dats_downloaded[active] = xmlFile
        os.remove(os.path.expanduser("~") + "/.gromlist/" + zip_name)

    # If it doesn't exist, create the folder for the images of the games
    xmlFile = dats_downloaded[active]
    document = xml.dom.minidom.parse(xmlFile)
    global dat_name
    if document.getElementsByTagName("imFolder"):
        dat_name = document.getElementsByTagName("imFolder")[0].firstChild.data
    else:
        dat_name = document.getElementsByTagName("datName")[0].firstChild.data
    folder = img_folder + "/" + dat_name + "/"
    if not os.path.exists(folder):
        os.mkdir(folder)

    add_games(document, folder)


def add_games(document, folder):
    """Add the release number and title of each game to the model and create the
    list of games"""
    # First we clear the data, in case another dat was selected before
    global model
    model.clear()
    games.clear()

    read_tags()

    img_location = document.getElementsByTagName("imURL")[0].firstChild.data
    num_games = 0
    num_roms = 0
    for game in document.getElementsByTagName("game"):
        num_games = num_games + 1

        # Create the game object from the xml data
        gameObj = Game()
        gameObj.imageNumber = game.getElementsByTagName("imageNumber")[0].firstChild.data
        gameObj.releaseNumber = game.getElementsByTagName("releaseNumber")[0].firstChild.data
        gameObj.title = game.getElementsByTagName("title")[0].firstChild.data
        gameObj.title = gameObj.title[0:72]
        gameObj.title = gameObj.title.replace("&", "&amp;")
        gameObj.publisher = game.getElementsByTagName("publisher")[0].firstChild.data
        gameObj.location = game.getElementsByTagName("location")[0].firstChild.data
        gameObj.sourceRom = game.getElementsByTagName("sourceRom")[0].firstChild.data
        gameObj.language = ""
        bin_languages = decimal_to_binary(int(game.getElementsByTagName("language")[0].firstChild.data))
        bin_languages = bin_languages.rjust(NUMBER_LANGUAGES, '0')
        bin_languages = bin_languages[::-1]
        for i in range(NUMBER_LANGUAGES):
            if bin_languages[i] == '1':
                if gameObj.language == "":
                    gameObj.language = LANGUAGES[i]
                else:
                    gameObj.language = gameObj.language + " / " + LANGUAGES[i]
        gameObj.romCRC = game.getElementsByTagName("romCRC")[0].firstChild.data.upper()
        gameObj.found = False

        global crcs
        if crcs.has_key(gameObj.romCRC):
            gameObj.found = True
            num_roms = num_roms + 1

        games[int(gameObj.releaseNumber)] = gameObj

        # Add the info to the model for the treeview to display it
        iter = model.insert_before(None, None, None)
        if COUNTRY_CODES.has_key(int(gameObj.location)):
            code = COUNTRY_CODES[int(gameObj.location)]
            gameObj.location = COUNTRY_NAMES[int(gameObj.location)]
        else:
            gameObj.location = _("Unknown")
            code = "xx"
        imgURL = "/usr/share/gromlist/images/flags/" +  code + ".png"
        imageLoc = gtk.gdk.pixbuf_new_from_file(imgURL)
        imageLoc.set_data("country", code)
        imageLoc.set_data("release", int(gameObj.releaseNumber))
        if gameObj.found:
            imageHaveRom = gtk.gdk.pixbuf_new_from_file("/usr/share/gromlist/images/rom.png")
            imageHaveRom.set_data("have_rom", True)
        else:
            imageHaveRom = gtk.gdk.pixbuf_new_from_file("/usr/share/gromlist/images/no_rom.png")
            imageHaveRom.set_data("have_rom", False)
        imageHaveRom.set_data("release", int(gameObj.releaseNumber))

        model.set_value(iter, 0, imageHaveRom)
        model.set_value(iter, 1, imageLoc)
        model.set_value(iter, 2, int(gameObj.releaseNumber))
        if gameObj.found:
            model.set_value(iter, 3, "<b>" + gameObj.title + "</b>")
        else:
            model.set_value(iter, 3, gameObj.title)

    # When we finish adding the games to the treeview, we select the first one,
    # write the 'Ready' message at the status bar, set the stats, and begin
    # downloading the images using another thread
    display_selected_game(None)

    statusbar.push(statusbar.get_context_id("Ready"), _("Ready"))

    lbl_total.set_text(str(num_games) + _(" games in the dat"))
    lbl_roms.set_text(str(num_roms) + _(" roms"))
    lbl_buyed.set_text(str(len(buyed)) + _(" buyed games"))
    lbl_played.set_text(str(len(played)) + _(" played games"))
    lbl_wanted.set_text(str(len(wanted)) + _(" wanted games"))

    for downloader in downloaders:
        if downloader:
            downloader.stop = True

    downloader = Downloader(games, img_location, folder)
    downloaders.append(downloader)
    downloader.start()


class Downloader(threading.Thread):
    def __init__(self, games, img_location, folder):
        threading.Thread.__init__(self)
        self.games = games
        self.img_location = img_location
        self.folder = folder
        self.stop = False

    def run(self):
        for release_number in self.games.keys():
            if self.stop:
                statusbar.push(statusbar.get_context_id("Ready"), _("Ready"))
                return

            try:
                gameObj = self.games[int(release_number)]
            except:
                pass

            img_range = get_range(int(gameObj.imageNumber))

            if not os.path.exists(self.folder + img_range):
                os.mkdir(self.folder + img_range)

            input1 = self.img_location + img_range + "/" + gameObj.imageNumber + "a.png"
            input2 = self.img_location + img_range + "/" + gameObj.imageNumber + "b.png"

            output1 = self.folder + img_range + "/" + gameObj.imageNumber + "a.png"
            output2 = self.folder + img_range + "/" + gameObj.imageNumber + "b.png"

            if not os.path.exists(output1):
                statusbar.push(statusbar.get_context_id("Downloading images"), _("Downloading images for ") + gameObj.releaseNumber + " - " + gameObj.title)
                try:
                    download(input1, output1)
                except:
                    pass

            if not os.path.exists(output2):
                statusbar.push(statusbar.get_context_id("Downloading images"), _("Downloading images for ") + gameObj.releaseNumber + " - " + gameObj.title)
                try:
                    download(input2, output2)
                except:
                    pass

        statusbar.push(statusbar.get_context_id("Ready"), _("Ready"))


def get_crc(file_name):
    bin = struct.pack('!l', zlib.crc32(file(file_name, 'r').read()))
    return binascii.hexlify(bin).upper()


def compare_have_rom(model, iter1, iter2, user_data=None):
    """Method used for the comparation of the 'have rom' column from the
    treeview."""
    (c, order) = model.get_sort_column_id()
    if c < 0:
        return 0

    x_rom = model.get_value(iter1, c).get_data("have_rom")
    y_rom = model.get_value(iter2, c).get_data("have_rom")

    x_release = model.get_value(iter1, c).get_data("release")
    y_release = model.get_value(iter2, c).get_data("release")

    if x_rom < y_rom:
        return -1
    if x_rom == y_rom:
        if x_release < y_release:
            return -1
        if x_release > y_release:
            return 1
        return 0
    return 1


def compareLocs(model, iter1, iter2, user_data=None):
    """Method used for the comparation of the location colum from the
    treeview."""
    (c, order) = model.get_sort_column_id()
    if c < 0:
        return 0

    x_country = model.get_value(iter1, c).get_data("country")
    y_country = model.get_value(iter2, c).get_data("country")

    x_release = model.get_value(iter1, c).get_data("release")
    y_release = model.get_value(iter2, c).get_data("release")

    if x_country < y_country:
        return -1
    if x_country == y_country:
        if x_release < y_release:
            return -1
        if x_release > y_release:
            return 1
        return 0
    return 1


def wanted_tag_selected(widget):
    global releaseNumber
    if widget.get_active():
        wanted[releaseNumber] = True
    elif wanted.has_key(releaseNumber):
        wanted.pop(releaseNumber)

def buyed_tag_selected(widget):
    global releaseNumber
    if widget.get_active():
        buyed[releaseNumber] = True
    elif buyed.has_key(releaseNumber):
        buyed.pop(releaseNumber)


def played_tag_selected(widget):
    global releaseNumber
    if widget.get_active():
        played[releaseNumber] = True
    elif played.has_key(releaseNumber):
        played.pop(releaseNumber)


def main_quit(obj1, obj2):
    """Method called when the user closes the application. It stops the thread
    and gtk's main loop."""
    global model
    model.clear()
    for downloader in downloaders:
        if downloader:
            downloader.stop = True
    write_tags()
    gtk.main_quit()



def create_gui():
    """Creates the user interface."""
    # Create the main window
    global window
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.maximize()
    window.set_title("Gromlist 0.3.2")
    window.connect("delete_event", main_quit)
    window.set_icon(gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/gromlist.svg"))

    # We are going to have 2 rows, one for the content, and one for the status
    # bar
    mainVbox = gtk.VBox(homogeneous=False, spacing=0)
    window.add(mainVbox)


    # The content is divided in two sections: the left side is for the treeview
    # with the list of games, the combo box with the dats and the filters; the
    # right side for the details of the selected game
    contentHbox = gtk.HBox(False, 0)
    mainVbox.pack_start(contentHbox, expand=True, fill=True)

    # Status bar
    statusbar.push(statusbar.get_context_id("Loading application"), _("Loading application"))
    mainVbox.pack_start(statusbar, expand=False, fill=True)


    # VBox for the lef side of the GUI
    leftVbox = gtk.VBox(False, 0)
    contentHbox.pack_start(leftVbox, expand=True, fill=True)

    # Scroll bars for the tree view
    scrollwindow = gtk.ScrolledWindow()
    scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    leftVbox.pack_start(scrollwindow, expand=True, fill=True)


    # Define the view for the model
    global view
    view = gtk.TreeView(model)
    renderer = gtk.CellRendererText()
    rendererImg = gtk.CellRendererPixbuf()
    colFound = gtk.TreeViewColumn("", rendererImg, pixbuf=0)
    colFound.set_sort_column_id(0)
    model.set_sort_func(0, compare_have_rom)
    view.append_column(colFound)
    colLoc = gtk.TreeViewColumn("", rendererImg, pixbuf=1)
    colLoc.set_sort_column_id(1)
    model.set_sort_func(1, compareLocs)
    view.append_column(colLoc)
    colNumber = gtk.TreeViewColumn("#", renderer, text=2)
    colNumber.set_sort_column_id(2)
    view.append_column(colNumber)
    colName = gtk.TreeViewColumn(_("Name"), renderer, markup=3)
    colName.set_sort_column_id(3)
    view.append_column(colName)
    view.set_rules_hint(True)
    view.set_search_column(3)
    scrollwindow.add(view)


    # Whenever the user selects a game, call the function which shows its info
    selection = view.get_selection()
    selection.connect("changed", display_selected_game)

    # Combobox at the end of the left side, to show the available dats
    global comboboxDat
    comboboxDat = gtk.combo_box_new_text()
    comboboxDat.connect("changed", display_selected_dat)
    dats = cfg.items("Dats")
    dats.sort()

    for name, value in dats:
        if name.startswith("name"):
            comboboxDat.append_text(value)
    leftVbox.pack_start(comboboxDat, expand=False)


    # The filters frame
    listFilters = gtk.VBox(False, 0)

    global written_text
    written_text = ""
    hbox_name_filter = gtk.HBox(False, 0)
    lbl_filter_name = gtk.Label(_("Name: "))
    name_entry = gtk.Entry()
    name_entry.connect("changed", name_written)
    hbox_name_filter.pack_start(lbl_filter_name, False, False, 5)
    hbox_name_filter.pack_start(name_entry, False, False, 5)
    listFilters.pack_start(hbox_name_filter)

    hbox_location_filter = gtk.HBox(False, 0)
    lbl_filter_location = gtk.Label(_("Location: "))
    hbox_location_filter.pack_start(lbl_filter_location, False, False, 5)
    global show_locations
    show_locations = []
    for country in COUNTRY_CODES.values():
        location_button = gtk.CheckButton()
        location_button.connect("toggled", location_selected, country)
        imgURL = "/usr/share/gromlist/images/flags/" +  country + ".png"
        image = gtk.Image()
        image.set_from_file(imgURL)
        hbox_location_filter.pack_start(image, False, False, 0)
        hbox_location_filter.pack_start(location_button, False, False, 0)
        hbox_location_filter.pack_start(gtk.HBox(), False, False, 5)
    listFilters.pack_start(hbox_location_filter)

    global rom_filters
    rom_filters = []
    hbox_rom_filter = gtk.HBox(False, 0)
    lbl_filter_rom = gtk.Label(_("With rom: "))
    image_rom = gtk.Image()
    image_rom.set_from_file("/usr/share/gromlist/images/rom.png")
    image_no_rom = gtk.Image()
    image_no_rom.set_from_file("/usr/share/gromlist/images/not_rom.png")
    rom_button = gtk.CheckButton()
    rom_button.connect("toggled", just_rom_selected, True)
    no_rom_button = gtk.CheckButton()
    no_rom_button.connect("toggled", just_rom_selected, False)
    hbox_rom_filter.pack_start(lbl_filter_rom, False, False, 5)
    hbox_rom_filter.pack_start(image_rom, False, False)
    hbox_rom_filter.pack_start(rom_button, False, False)
    hbox_rom_filter.pack_start(image_no_rom, False, False)
    hbox_rom_filter.pack_start(no_rom_button, False, False)
    listFilters.pack_start(hbox_rom_filter)

    global buyed_filter
    buyed_filter = []
    hbox_buyed_filter = gtk.HBox(False, 0)
    lbl_filter_buyed = gtk.Label(_("Buyed: "))
    image_buyed = gtk.Image()
    image_buyed.set_from_file("/usr/share/gromlist/images/buyed.png")
    image_no_buyed = gtk.Image()
    image_no_buyed.set_from_file("/usr/share/gromlist/images/not_buyed.png")
    buyed_button = gtk.CheckButton()
    buyed_button.connect("toggled", just_buyed_selected, True)
    no_buyed_button = gtk.CheckButton()
    no_buyed_button.connect("toggled", just_buyed_selected, False)
    hbox_buyed_filter.pack_start(lbl_filter_buyed, False, False, 5)
    hbox_buyed_filter.pack_start(image_buyed, False, False)
    hbox_buyed_filter.pack_start(buyed_button, False, False)
    hbox_buyed_filter.pack_start(image_no_buyed, False, False)
    hbox_buyed_filter.pack_start(no_buyed_button, False, False)
    listFilters.pack_start(hbox_buyed_filter)

    global played_filter
    played_filter = []
    hbox_played_filter = gtk.HBox(False, 0)
    lbl_filter_played = gtk.Label(_("Played: "))
    image_played = gtk.Image()
    image_played.set_from_file("/usr/share/gromlist/images/played.png")
    image_no_played = gtk.Image()
    image_no_played.set_from_file("/usr/share/gromlist/images/not_played.png")
    played_button = gtk.CheckButton()
    played_button.connect("toggled", just_played_selected, True)
    no_played_button = gtk.CheckButton()
    no_played_button.connect("toggled", just_played_selected, False)
    hbox_played_filter.pack_start(lbl_filter_played, False, False, 5)
    hbox_played_filter.pack_start(image_played, False, False)
    hbox_played_filter.pack_start(played_button, False, False)
    hbox_played_filter.pack_start(image_no_played, False, False)
    hbox_played_filter.pack_start(no_played_button, False, False)
    listFilters.pack_start(hbox_played_filter)

    global wanted_filter
    wanted_filter = []
    hbox_wanted_filter = gtk.HBox(False, 0)
    lbl_filter_wanted = gtk.Label(_("Wanted: "))
    image_wanted = gtk.Image()
    image_wanted.set_from_file("/usr/share/gromlist/images/wanted.png")
    image_no_wanted = gtk.Image()
    image_no_wanted.set_from_file("/usr/share/gromlist/images/not_wanted.png")
    wanted_button = gtk.CheckButton()
    wanted_button.connect("toggled", just_wanted_selected, True)
    no_wanted_button = gtk.CheckButton()
    no_wanted_button.connect("toggled", just_wanted_selected, False)
    hbox_wanted_filter.pack_start(lbl_filter_wanted, False, False, 5)
    hbox_wanted_filter.pack_start(image_wanted, False, False)
    hbox_wanted_filter.pack_start(wanted_button, False, False)
    hbox_wanted_filter.pack_start(image_no_wanted, False, False)
    hbox_wanted_filter.pack_start(no_wanted_button, False, False)
    listFilters.pack_start(hbox_wanted_filter)

    alignFilters = gtk.Alignment(xalign=0, yalign=0.5)
    alignFilters.add(listFilters)
    frame = gtk.Frame()
    frame.set_border_width(1)
    frame.add(alignFilters)
    expander = gtk.Expander(_("Filter list by:"))
    expander.add(frame)
    leftVbox.pack_start(expander, expand=False, fill=False)

    vbox_stats = gtk.VBox(False, 0)
    hbox_stats_row = gtk.HBox(False, 0)
    hbox_stats_row.pack_start(lbl_total, False, False, 5)
    vbox_stats.pack_start(hbox_stats_row)
    hbox_stats_row = gtk.HBox(False, 0)
    hbox_stats_row.pack_start(lbl_roms, False, False, 5)
    vbox_stats.pack_start(hbox_stats_row)
    hbox_stats_row = gtk.HBox(False, 0)
    hbox_stats_row.pack_start(lbl_buyed, False, False, 5)
    vbox_stats.pack_start(hbox_stats_row)
    hbox_stats_row = gtk.HBox(False, 0)
    hbox_stats_row.pack_start(lbl_played, False, False, 5)
    vbox_stats.pack_start(hbox_stats_row)
    hbox_stats_row = gtk.HBox(False, 0)
    hbox_stats_row.pack_start(lbl_wanted, False, False, 5)
    vbox_stats.pack_start(hbox_stats_row)
    frame = gtk.Frame()
    frame.set_border_width(1)
    frame.add(vbox_stats)
    expander = gtk.Expander(_("Stats"))
    expander.add(frame)
    leftVbox.pack_start(expander, expand=False, fill=False)

    # The right side is a vbox. At the top an hbox with the images, below a
    # table with the details of the game and at the bottom the widgets for the
    # filtering of the list of games.
    rightVbox = gtk.VBox(homogeneous=False, spacing=0)

    detailsVbox = gtk.VBox(homogeneous=False, spacing=0)

    alignDetails = gtk.Alignment(xalign=0, yalign=0.2, xscale=0.0, yscale=0.0)
    alignDetails.add(detailsVbox)


    imagesHbox = gtk.HBox(False, 0)

    image1.set_from_file("/usr/share/gromlist/images/nonea.png")
    imagesHbox.pack_start(image1, padding=10)
    image2.set_from_file("/usr/share/gromlist/images/noneb.png")
    imagesHbox.pack_start(image2, padding=10)

    detailsVbox.pack_start(imagesHbox, expand=False, padding=30)

    listFields = gtk.VBox(False, 0)

    lblTitle.set_use_markup(True)
    lblTitle.set_markup("<span size=\"x-large\" weight=\"bold\">---</span>")
    lblTitle.set_line_wrap(True)
    listFields.pack_start(lblTitle)
    listFields.pack_start(lblLocation)
    listFields.pack_start(lblPublisher)
    listFields.pack_start(lblSource)
    lblLanguage.set_line_wrap(True)
    listFields.pack_start(lblLanguage)

    detailsVbox.pack_start(listFields, expand=False)

    rightVbox.pack_start(alignDetails, False, False, 5)

    # User tags for this game
    gameTags = gtk.VBox(False, 0)

    hbox_buyed_tag = gtk.HBox(False, 0)
    imgURL = "/usr/share/gromlist/images/buyed.png"
    image = gtk.Image()
    image.set_from_file(imgURL)
    hbox_buyed_tag.pack_start(image, False, False, 0)
    lbl_buyed_tag = gtk.Label(_(" Buyed "))
    hbox_buyed_tag.pack_start(lbl_buyed_tag, False, False, 5)
    buyed_tag_button.connect("toggled", buyed_tag_selected)
    hbox_buyed_tag.pack_start(buyed_tag_button, False, False, 0)
    gameTags.pack_start(hbox_buyed_tag)

    hbox_played_tag = gtk.HBox(False, 0)
    imgURL = "/usr/share/gromlist/images/played.png"
    image = gtk.Image()
    image.set_from_file(imgURL)
    hbox_played_tag.pack_start(image, False, False, 0)
    lbl_played_tag = gtk.Label(_(" Played "))
    hbox_played_tag.pack_start(lbl_played_tag, False, False, 5)
    played_tag_button.connect("toggled", played_tag_selected)
    hbox_played_tag.pack_start(played_tag_button, False, False, 0)
    gameTags.pack_start(hbox_played_tag)

    hbox_wanted_tag = gtk.HBox(False, 0)
    imgURL = "/usr/share/gromlist/images/wanted.png"
    image = gtk.Image()
    image.set_from_file(imgURL)
    hbox_wanted_tag.pack_start(image, False, False, 0)
    lbl_wanted_tag = gtk.Label(_(" Wanted "))
    hbox_wanted_tag.pack_start(lbl_wanted_tag, False, False, 5)
    wanted_tag_button.connect("toggled", wanted_tag_selected)
    hbox_wanted_tag.pack_start(wanted_tag_button, False, False, 0)
    gameTags.pack_start(hbox_wanted_tag)

    alignFilters = gtk.Alignment(xalign=0, yalign=0.5)
    alignFilters.add(gameTags)
    frame = gtk.Frame(_("Tags:"))
    frame.set_border_width(1)
    frame.add(alignFilters)
    rightVbox.pack_start(frame, expand=False, fill=False)


    contentHbox.pack_start(rightVbox, False, False, 5)

    # Show the window and all its children
    window.show_all()


def just_rom_selected(widget, rom):
    """Method called when a checkbox of the rom filter set is checked or
    unchecked, to filter the view and show only the games we have or don't have
    on the hard disk."""
    global rom_filters
    if widget.get_active():
        rom_filters.append(rom)
    else:
        rom_filters.remove(rom)

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def just_played_selected(widget, played):
    """Method called when a checkbox of the played filter set is checked or
    unchecked, to filter the view and show only the games the user played."""
    global played_filter
    if widget.get_active():
        played_filter.append(played)
    else:
        played_filter.remove(played)

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def just_wanted_selected(widget, wanted):
    """Method called when a checkbox of the played filter set is checked or
    unchecked, to filter the view and show only the games the user wants."""
    global wanted_filter
    if widget.get_active():
        wanted_filter.append(wanted)
    else:
        wanted_filter.remove(wanted)

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def just_buyed_selected(widget, buyed):
    """Method called when a checkbox of the played filter set is checked or
    unchecked, to filter the view and show only the games the user buyed."""
    global buyed_filter
    if widget.get_active():
        buyed_filter.append(buyed)
    else:
        buyed_filter.remove(buyed)

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def filter(model, iter):
    """Combines all filters to show only the roms the user wants on the list."""
    response = True
    global rom_filters
    global written_text
    global show_locations
    global buyed_filter
    global played_filter
    global wanted_filter

    if rom_filters:
        response = response and filter_by_rom(model, iter, rom_filters)

    if written_text:
        response = response and filter_by_name(model, iter, written_text)

    if show_locations:
        response = response and filter_by_country(model, iter, show_locations)

    if buyed_filter:
        response = response and filter_by_buyed(model, iter, buyed_filter)

    if played_filter:
        response = response and filter_by_played(model, iter, played_filter)

    if wanted_filter:
        response = response and filter_by_wanted(model, iter, wanted_filter)

    return response


def filter_by_rom(model, iter, roms):
    """Filters the list depending on whether we have the rom for that game."""
    for rom_filter in roms:
        if model.get_value(iter, 0):
            if model.get_value(iter, 0).get_data("have_rom") == rom_filter:
                return True
    return False


def name_written(widget):
    """Method called when something is written in the name entry to filter
    list."""
    global written_text
    written_text = widget.get_text()

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def filter_by_name(model, iter, name):
    """Filters the list using the name of the game and the text written in
    the name entry."""
    if model.get_value(iter, 3):
        if model.get_value(iter, 3).lower().find(name.lower()) >= 0:
            return True
    return False


def filter_by_buyed(model, iter, buyed_filters):
    """Filters the list showing only the ones the user buyed or not."""
    for buyed_filter in buyed_filters:
        if model.get_value(iter, 2):
            if buyed_filter and buyed.has_key(model.get_value(iter, 2)):
                return True
            if not buyed_filter and not buyed.has_key(model.get_value(iter, 2)):
                return True
    return False


def filter_by_played(model, iter, played_filters):
    """Filters the list showing only the ones the user played or not."""
    for played_filter in played_filters:
        if model.get_value(iter, 2):
            if played_filter and played.has_key(model.get_value(iter, 2)):
                return True
            if not played_filter and not played.has_key(model.get_value(iter, 2)):
                return True
    return False


def filter_by_wanted(model, iter, wanted_filters):
    """Filters the list showing only the ones the user wants or not."""
    for wanted_filter in wanted_filters:
        if model.get_value(iter, 2):
            if wanted_filter and wanted.has_key(model.get_value(iter, 2)):
                return True
            if not wanted_filter and not wanted.has_key(model.get_value(iter, 2)):
                return True
    return False


def location_selected(widget, country):
    """Method called when a checkbox with a location is selected, to filter
    the view and show only the games of that location."""
    global show_locations
    if widget.get_active():
        show_locations.append(country)
    else:
        show_locations.remove(country)

    model_filter = model.filter_new()
    model_filter.set_visible_func(filter)
    view.set_model(gtk.TreeModelSort(model_filter))


def no_filter(model, iter):
    """Filter function. It always returns True so that no value is hidden."""
    return True


def filter_by_country(model, iter, locations):
    """Filters the list using the country of the game."""
    for location in locations:
        if model.get_value(iter, 1):
            if model.get_value(iter, 1).get_data("country") == location:
                return True
    return False


def write_default_config():
    config_file = open(os.path.expanduser("~") + "/.gromlist/conf", "w")
    default_config = """[General]
; Folder where your roms are stored
rom_folder = ~/.gromlist/roms

; Folder where the images are stored
img_folder = ~/.gromlist/images

; Number of the dat to be loaded by default
default_dat = 0



[Dats]
; List of the collections the user can select from.
name0 = DS Collection
url0 = http://www.advanscene.com/offline/datas/ADVANsCEne_NDS_S.zip

name1 = PSP Collection
url1 = http://www.advanscene.com/offline/datas/ADVANsCEne_PSP.zip

;name2 = Wii Collection
;url2 = http://jmichel.servant.free.fr/OffLineList/Wii_Collection.zip"""
    config_file.write(default_config)
    config_file.close()



# i18n
gettext.install("gromlist")


COUNTRY_CODES = {}
COUNTRY_CODES[0] = "eu"
COUNTRY_CODES[1] = "us"
COUNTRY_CODES[2] = "de"
COUNTRY_CODES[3] = "cn"
COUNTRY_CODES[4] = "es"
COUNTRY_CODES[5] = "fr"
COUNTRY_CODES[6] = "it"
COUNTRY_CODES[7] = "jp"
COUNTRY_CODES[19] = "au"
COUNTRY_CODES[22] = "kr"

COUNTRY_NAMES = {}
COUNTRY_NAMES[0] = _("Europe")
COUNTRY_NAMES[1] = _("USA")
COUNTRY_NAMES[2] = _("Germany")
COUNTRY_NAMES[3] = _("China")
COUNTRY_NAMES[4] = _("Spain")
COUNTRY_NAMES[5] = _("France")
COUNTRY_NAMES[6] = _("Italy")
COUNTRY_NAMES[7] = _("Japan")
COUNTRY_NAMES[19] = _("Australia")
COUNTRY_NAMES[22] = _("South Korea")

NUMBER_LANGUAGES = 17
LANGUAGES = {}
LANGUAGES[0] = _("French")
LANGUAGES[1] = _("English")
LANGUAGES[2] = _("Chinese")
LANGUAGES[3] = _("Danish")
LANGUAGES[4] = _("Dutch")
LANGUAGES[5] = _("Finnish")
LANGUAGES[6] = _("German")
LANGUAGES[7] = _("Italian")
LANGUAGES[8] = _("Japanese")
LANGUAGES[9] = _("Norwegian")
LANGUAGES[10] = _("Polish")
LANGUAGES[11] = _("Portuguese")
LANGUAGES[12] = _("Spanish")
LANGUAGES[13] = _("Swedish")
LANGUAGES[14] = _("Unknown")
LANGUAGES[15] = _("Unknown")
LANGUAGES[16] = _("Korean")


# Read the configuration values from the config file. If the file does not exist
# create it with the default values
cfg = ConfigParser.SafeConfigParser()
if not os.path.exists(os.path.expanduser("~") + "/.gromlist/conf"):
    if not os.path.exists(os.path.expanduser("~") + "/.gromlist/"):
        os.mkdir(os.path.expanduser("~") + "/.gromlist/")
        write_default_config()

cfg.readfp(file(os.path.expanduser("~") + "/.gromlist/conf"))

try:
    rom_folder = cfg.get("General", "rom_folder").replace("~", os.path.expanduser("~"))
except (ConfigParser.NoOptionError):
    write_default_config()
    cfg.readfp(file(os.path.expanduser("~") + "/.gromlist/conf"))
    rom_folder = cfg.get("General", "rom_folder").replace("~", os.path.expanduser("~"))
    
try:
    img_folder = cfg.get("General", "img_folder").replace("~", os.path.expanduser("~"))
except (ConfigParser.NoOptionError):
    write_default_config()
    cfg.readfp(file(os.path.expanduser("~") + "/.gromlist/conf"))
    img_folder = cfg.get("General", "img_folder").replace("~", os.path.expanduser("~"))

if not os.path.exists(rom_folder):
    os.mkdir(rom_folder)

if not os.path.exists(img_folder):
    os.mkdir(img_folder)


games = {}
wanted = {}
buyed = {}
played = {}
dat_name = ""
dats_downloaded = {}
downloaders = []

# Create the user interface
model = gtk.TreeStore(gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gobject.TYPE_INT, gobject.TYPE_STRING)
statusbar = gtk.Statusbar()
wanted_tag_button = gtk.CheckButton()
played_tag_button = gtk.CheckButton()
buyed_tag_button = gtk.CheckButton()
image1 = gtk.Image()
image2 = gtk.Image()
lblTitle = gtk.Label()
lblLocation = gtk.Label(_("Location: ---"))
lblPublisher = gtk.Label(_("Publisher: ---"))
lblSource = gtk.Label(_("Source: ---"))
lblLanguage = gtk.Label(_("Language: ---"))
lbl_total = gtk.Label("0" + _(" games in the dat"))
lbl_roms = gtk.Label("0" + _(" downloaded games"))
lbl_buyed = gtk.Label(str(len(buyed)) + _(" buyed games"))
lbl_played = gtk.Label(str(len(played)) + _(" played games"))
lbl_wanted = gtk.Label(str(len(wanted)) + _(" wanted games"))
create_gui()


# Calculate the CRC of the files in the rom folder
statusbar.push(statusbar.get_context_id("Calculating CRC"), _("Calculating CRC"))
crcs = {}
for rom_file in os.listdir(rom_folder):
    crcs[get_crc(rom_folder + "/" + rom_file)] = rom_folder + "/" + rom_file


# Search for the dat to load by default
default_dat = cfg.get("General", "default_dat")
display_selected_dat(selected=default_dat)

gtk.gdk.threads_init()

gtk.main()
